#ifndef _CLOCK_CLOCK_H_
#define _CLOCK_CLOCK_H_


namespace time
{

enum day_t : unsigned char
{
  MONDAY    = 0,
  TUESDAY   = 1,
  WEDNESDAY = 2,
  THURSDAY  = 3,
  FRIDAY    = 4,
  SATURDAY  = 5,
  SUNDAY    = 6
};

enum month_t : unsigned char
{
  JANUARY   = 0,
  FEBRUARY  = 1,
  MARCH     = 2,
  APRIL     = 3,
  MAY       = 4,
  JUNE      = 5,
  JULY      = 6,
  AUGUST    = 7,
  SEPTEMBER = 8,
  OCTOBER   = 9,
  NOVEMBER  = 10,
  DECEMBER  = 11
};

struct time_t
{
  unsigned char hour;
  unsigned char minute;
  unsigned char second;

  void increase_hour(void)
  {
    switch (hour)
    {
      case 23:
      {
        hour = 0;
        break;
      }
      default:
       ++hour;
    }
  }

  void increase_minute(void)
  {
    switch (minute)
    {
      case 59:
      {
        minute = 0;
        increase_hour();
        break;
      }
      default:
        ++minute;
    }
  }

  void increase_second(void)
  {
    switch (second)
    {
      case 59:
      {
        second = 0;
        increase_minute();
      }
      default:
        ++second;
    }
  }

  void decrease_hour(void)
  {
    switch (hour)
    {
      case 0:
      {
        hour = 23;
        break;
      }
      default:
       --hour;
    }
  }

  void decrease_minute(void)
  {
    switch (minute)
    {
      case 0:
      {
        minute = 59;
        decrease_hour();
        break;
      }
      default:
        --minute;
    }
  }

  void decrease_second(void)
  {
    switch (second)
    {
      case 0:
      {
        second = 59;
        decrease_minute();
      }
      default:
        --second;
    }
  }

  time_t& operator +=(unsigned long seconds)
  {
    seconds += second;
    second  = seconds % 60;
    seconds = seconds / 60 + minute;
    minute  = seconds % 60;
    seconds = seconds / 60 + hour;
    hour    = seconds % 24;

    return *this;
  }

  time_t operator +(unsigned long seconds)
  {
    time_t date = *this;
    return date += seconds;
  }

  bool operator ==(time_t const& tim) const
  { return hour == tim.hour && minute == tim.minute && second == tim.second; }
};

} // time

namespace clock
{

class abstract_clock
{
public:

  virtual void update(unsigned long delta) = 0;

  virtual void blink_hour(bool status) = 0;
  virtual void blink_minute(bool status) = 0;
  virtual void blink_second(bool status) = 0;

  time::time_t& get_start_time(void)
  { return _start_time; }

  time::time_t const& get_start_time(void) const
  { return _start_time; }

  time::time_t const get_current_time(void) const
  { return _current_time; }

protected:

  time::time_t _start_time, _current_time;
};

} // clock

#endif // _CLOCK_CLOCK_H_
